package stack;

//输入一句运算的表达式，得出结果
public class Calculate {
	public static void main(String[] args) {
		//输入的表达式
		String expression = "3.1+2*6-2";
		//1.创建两个栈-存放数组的栈；存放符号的栈
		ArrayStack2 numStack = new ArrayStack2(10);
		ArrayStack2 operStack = new ArrayStack2(10);
		//2.定义需要的相关变量
		int index = 0;//用于扫描表达式
		float num1 = 0;//用于计算的数
		float num2 = 0;//用于计算
		int oper = 0;//运算符
		float result = 0;//结果
		char ch = ' ';//存放每次扫描的字符
		String keepNum = "";//用于拼接多位数
		//3.循环扫描表达式
		while (true) {
			//3.1依次得到表达式中的每个字符
			ch = expression.substring(index, index + 1).charAt(0);

			//3.2判断ch是什么，并作相应的处理
			if (operStack.isOper(ch)) {//如果是运算符
				//判断符号栈是否为空
				if (!operStack.isEmpty()) {
					//不为空，相应处理
                    /*如果当前的操作伏的优先级小于或等于栈中的操作符，
                   就需要从数字栈中pop出两个数，从符号栈pop一个符号，进行运算
                   最后把运算结果，和 ch 中存储的运算符分别存入*/
					if (operStack.pripority(ch) <= operStack.pripority(operStack.peek())) {
						num1 = numStack.pop();
						num2 = numStack.pop();
						oper = (int) operStack.pop();
						result = numStack.cal(num1, num2, oper);
						numStack.push(result);
						operStack.push(ch);
					} else {
						/*如果当前的操作伏的优先级大于栈中的操作符，直接入栈*/
						operStack.push(ch);
					}
				} else {
					operStack.push(ch);
				}
			} else {//把数字入栈
				//因为ch是字符类型，在Ascii表中 字符 1 比 数字 1 大 48，虚减掉。
				//numStack.push(ch - 48);

                /*多位数运算
                  1.当发现一个数字时，不能立即入栈，可能时多位数
                  2.在处理数时，需要向后多看一位，如果是数就拼接，如果是符号就入栈
                  3.需要定义一个字符串变量，用来拼接多位数
                 */


				//处理多位数

				keepNum += ch;
				//判断下一个字符是不是数字，若是数字就继续扫描
				//如果是运算符就入栈
				if (index >= expression.length() - 1) {//判断是不是最后一位
					numStack.push(Integer.parseInt(keepNum));
				} else {
					if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
						//满足，则后一位是运算符
						numStack.push(Float.parseFloat(keepNum));
						//清空 keepnum
						keepNum = "";
					}
				}
			}
			//让index + 1，并判断是否到结尾
			index++;
			//index 从 0 开始，所以扫描完，index的值，应等于长度
			if (index >= expression.length()) {
				break;
			}

		}
		//4.当表达式扫描完毕，开始配对计算
		while (true) {
			//如果符号栈为空，则计算完成
			if (operStack.isEmpty()) {
				break;
			}
			//进行计算
			num1 = numStack.pop();
			num2 = numStack.pop();
			oper = (int) operStack.pop();
			result = numStack.cal(num1, num2, oper);
			numStack.push(result);
		}
		System.out.println("表达式的结果为：" + numStack.pop());
	}
}

//先创建一个栈
class ArrayStack2 {
	private int maxSize;//栈的大小
	private float[] stack;//数组，模拟栈，存储数据
	private int top = -1;//栈顶

	public ArrayStack2(int maxSize) {
		this.maxSize = maxSize;
		stack = new float[this.maxSize];
	}

	//判断是否满
	public boolean isFull() {
		return top == maxSize - 1;
	}

	//栈空
	public boolean isEmpty() {
		return top == -1;
	}

	//入栈
	public void push(float value) {
		//判断是否满
		if (isFull()) {
			System.out.println("栈满");
			return;
		}
		top++;

		stack[top] = value;
	}

	//出栈
	public float pop() {
		if (isEmpty()) {
			//抛出异常
			throw new RuntimeException("栈空");
		}
		float value = stack[top];
		top--;
		return value;
	}

	//遍历栈,需要从栈顶开始
	public void list() {
		if (isEmpty()) {
			throw new RuntimeException("栈空");
		}
		for (int i = top; i >= 0; i--) {
			System.out.println("stack[" + i + "]=" + stack[i]);
		}
	}

	//返回运算符的优先级，优先级用数字表示
	public float pripority(float oper) {
		if (oper == '*' || oper == '/') {
			return 1;
		} else if (oper == '-' || oper == '+') {
			return 0;
		} else {
			return -1;
		}
	}

	//判断是否是运算符
	public boolean isOper(char val) {
		return val == '+' || val == '-' || val == '*' || val == '/';
	}

	//计算的方法
	public float cal(float num1, float num2, int oper) {
		float result = 0;//计算结果
		switch (oper) {
			case '+':
				result = num2 + num1;
				break;
			case '-':
				result = num2 - num1;
				break;
			case '*':
				result = num2 * num1;
				break;
			case '/':
				result = num2 / num1;
				break;
			default:
				break;
		}
		return result;
	}

	//显示栈顶元素，不出栈
	public float peek() {
		return stack[top];
	}
}
